﻿using log4net;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
//using System.Net.WebSockets;
using System.Threading.Tasks;
using System.Timers;
using WebSocketSharp;

namespace CDV.MC.MatrixDriver.WebApp.Notify
{
    public interface IWebSocketManagerService
    {
        event EventHandler Notify;

        ILog Logger { get; set; }

        bool AddClientSocket(string clientIP);
        void RemoveClientSocket(string clientIP);
    }
    public class WebSocketManager : IWebSocketManagerService, IDisposable
    {
        private const string Ping = "Ping";
        public IDictionary<string, WebSocket> ClientNotifier { get; set; } = new Dictionary<string, WebSocket>();

        public event EventHandler Notify;

        public string ServerPath { get; set; }

        public ILog Logger { get; set; }

        private System.Timers.Timer tmrWatch;

        public WebSocketManager()
        {
            Logger = LogManager.GetLogger(typeof(WebSocketManager));

            tmrWatch = new System.Timers.Timer(3000);
            tmrWatch.Elapsed += TmrWatch_Elapsed;
            tmrWatch.Start();
        }

        private void TmrWatch_Elapsed(object sender, ElapsedEventArgs e)
        {
            try
            {
                foreach (var notify in ClientNotifier)
                {
                    ThreadPool.QueueUserWorkItem((parameter) =>
                    {
                        var notifyClient = (KeyValuePair<string, WebSocket>)parameter;
                        var pingData = string.Format("{0}-{1}", Ping, notifyClient.Key);
                        var result = notifyClient.Value.Ping(pingData);
                        Logger.InfoFormat("Web客户端[{0}]执行心跳检测, 发送数据：[{1}], 检测结果:{2}", notifyClient.Key, pingData, result);
                    }, notify);
                }
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("Web客户端心跳检测失败，异常信息如下：{0}", ex);
            }
        }

        public bool AddClientSocket(string clientIP)
        {

            try
            {
                var socketInstance = new WebSocket(ServerPath);
                //socketInstance.EmitOnPing = true;
                socketInstance.OnMessage += (sender, e) =>
                {
                    if (e.IsText)
                    {
                        if (!e.Data.StartsWith(Ping))
                        {
                            if (Notify != null)
                            {
                                Notify.Invoke(sender, e);
                            }
                        }
                    }                    
                };

                socketInstance.OnError += (sender, e) =>
                {
                    Notify.Invoke(sender, e);
                };

                socketInstance.OnOpen += (sender, e) =>
                {
                    Notify.Invoke(sender, e);
                };

                //矩阵服务关闭时，Socket连接会断开
                socketInstance.OnClose += (sender, e) =>
                {
                    Notify.Invoke(sender, e);
                };
                socketInstance.Connect();

                if (socketInstance.ReadyState == WebSocketState.Open)
                {
                    socketInstance.Send(clientIP);

                    ClientNotifier[clientIP] = socketInstance;
                    Logger.InfoFormat("Web客户端[{0}]的Socket连接创建成功", clientIP);
                    return true;
                }
                else
                {
                    Logger.ErrorFormat("Web客户端[{0}]的Socket连接创建失败，异常信息如下：{1}", clientIP, socketInstance.ReadyState);
                    return false;
                }
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("Web客户端[{0}]的Socket连接创建失败，异常信息如下：{1}", clientIP, ex);
                return false;
            }
        }

        public void RemoveClientSocket(string clientIP)
        {
            if (ClientNotifier.ContainsKey(clientIP))
            {
                if (ClientNotifier[clientIP].ReadyState == WebSocketState.Open)
                {
                    ClientNotifier[clientIP].Close(CloseStatusCode.Normal);
                }
                ClientNotifier.Remove(clientIP);
            }
        }

        public void Dispose()
        {
            try
            {
                tmrWatch.Stop();
                tmrWatch.Dispose();

                foreach (var item in ClientNotifier)
                {
                    item.Value.Close(CloseStatusCode.Normal);
                }
                ClientNotifier.Clear();
            }
            catch
            {
            }
        }
    }
}
